package com.ikunikun.service.impl;

import com.ikunikun.dto.GoodsSalesDTO;
import com.ikunikun.entity.Orders;
import com.ikunikun.exception.OrderBusinessException;
import com.ikunikun.mapper.OrderMapper;
import com.ikunikun.mapper.UserMapper;
import com.ikunikun.service.ReportService;
import com.ikunikun.service.WorkspaceService;
import com.ikunikun.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Array;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

	@Resource
	private OrderMapper orderMapper;
	@Resource
	private UserMapper userMapper;
	@Resource
	private WorkspaceService workspaceService;

	@Override
	public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
		// 判断end日期是否在begin之前，提升代买健壮性
		if (begin.isAfter(end)){
			throw new OrderBusinessException("输入数据非法");
		}

		// 封装日期
		ArrayList<LocalDate> localDates = new ArrayList<>();
		localDates.add(begin);
		while (!begin.equals(end)){
			begin = begin.plusDays(1);
			localDates.add(begin);
		};
		String localDateString = StringUtils.join(localDates, ", ");

		// 封装营业额
		ArrayList<Double> turnoverList = new ArrayList<>();
		for (LocalDate date : localDates) {
			LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
			LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
			// 查询条件， 日期，订单状态已完成，
			HashMap<String, Object> map = new HashMap<>();
			map.put("begin", beginTime);
			map.put("end", endTime);
			map.put("status", Orders.COMPLETED);
			Double turnover = orderMapper.sumByMap(map);
			turnover = turnover == null ? 0.0: turnover;
			turnoverList.add(turnover);
		}
		String turnoverString = StringUtils.join(turnoverList, ", ");
		return new TurnoverReportVO(localDateString, turnoverString);
	}

	/**
	 * 统计指定时间区间用户数量信息
	 * @param begin
	 * @param end
	 * @return
	 */
	@Override
	public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
		// 判断end日期是否在begin之前，提升代买健壮性
		if (begin.isAfter(end)){
			throw new OrderBusinessException("输入数据非法");
		}
		// 封装日期
		ArrayList<LocalDate> localDates = new ArrayList<>();
		localDates.add(begin);
		while (!begin.equals(end)){
			begin = begin.plusDays(1);
			localDates.add(begin);
		};
		String localDateString = StringUtils.join(localDates, ",");

		// 封装用户总量信息
		ArrayList<Integer> totalUserList = new ArrayList<>();
		// 封装用户变换信息
		ArrayList<Integer> newUserList = new ArrayList<>();

		for (LocalDate date : localDates) {
			LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
			LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);

			HashMap<String, Object> map = new HashMap<>();
			map.put("begin", beginTime);
			Integer totalUser = userMapper.countByMap(map);
			totalUserList.add(totalUser);

			map.put("end", endTime);
			Integer newUser = userMapper.countByMap(map);
			newUserList.add(newUser);
		}

		String totalUserSting = StringUtils.join(totalUserList, ",");
		String newUserString = StringUtils.join(newUserList, ",");

		return new UserReportVO(localDateString, totalUserSting, newUserString);
	}

	/**
	 * 订单统计
	 * @param begin
	 * @param end
	 * @return
	 */
	@Override
	public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) {
		// 判断end日期是否在begin之前，提升代买健壮性
		if (begin.isAfter(end)){
			throw new OrderBusinessException("输入数据非法");
		}
		// 封装日期
		ArrayList<LocalDate> localDates = new ArrayList<>();
		localDates.add(begin);
		while (!begin.equals(end)){
			begin = begin.plusDays(1);
			localDates.add(begin);
		};
		String localDateString = StringUtils.join(localDates, ",");

		// 遍历日期，查询每日的总订单数和有效订单数
		// 封装每日订单数
		ArrayList<Integer> orderCountList = new ArrayList<>();
		// 封装每日交易完成订单数
		ArrayList<Integer> validOrderCountList = new ArrayList<>();
		for (LocalDate date : localDates) {
			LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
			LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
			HashMap<String, Object> map = new HashMap<>();
			map.put("begin", beginTime);
			map.put("end", endTime);

			// 查询每天的订单总数
			Integer orderCount = orderMapper.countByMap(map);
			orderCountList.add(orderCount);

			// 查询每天的有效订单数
			map.put("status", Orders.COMPLETED);
			Integer validOrderCount = orderMapper.countByMap(map);
			validOrderCountList.add(validOrderCount);
		}

		Integer orderCount = orderCountList.stream().reduce(Integer::sum).get();
		Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();

		Double orderCompletionRate = 0.0;
		if (orderCount != 0){
			orderCompletionRate = validOrderCount.doubleValue() / orderCount.doubleValue();
		}

		return OrderReportVO.builder()
				.dateList(localDateString)
				.orderCountList(StringUtils.join(orderCountList, ","))
				.validOrderCountList(StringUtils.join(validOrderCountList, ","))
				.totalOrderCount(orderCount)
				.validOrderCount(validOrderCount)
				.orderCompletionRate(orderCompletionRate)
				.build();
	}

	/**
	 * 统计指定时间区间内的销量排名前10
	 * @param begin
	 * @param end
	 * @return
	 */
	@Override
	public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
		LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
		LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
		List<GoodsSalesDTO> salesTop = orderMapper.getSalesTop(beginTime, endTime);

		List<String> nameList = salesTop.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
		List<Integer> numberList = salesTop.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
		return SalesTop10ReportVO.builder()
				.nameList(StringUtils.join(nameList, ","))
				.numberList(StringUtils.join(numberList, ","))
				.build();
	}

	@Override
	public void export(HttpServletResponse response) {
		// 查数据库，获得营业数据
		LocalDate dateBegin = LocalDate.now().minusDays(30);
		LocalDate dateEnd = LocalDate.now().minusDays(1);
		BusinessDataVO businessDataVO = workspaceService.getBusinessData(
				LocalDateTime.of(dateBegin, LocalTime.MIN),
				LocalDateTime.of(dateEnd, LocalTime.MAX)
		);


		// 基于模板文件创建一个excel文件
		XSSFWorkbook excel = null;
		try {
			InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
			excel = new XSSFWorkbook(inputStream);
			// 通过POI将数据写入excel
			XSSFSheet sheet = excel.getSheetAt(0);
			sheet.getRow(1).getCell(1).setCellValue(dateBegin + " -- " + dateEnd);
			XSSFRow row = sheet.getRow(2);
			row.getCell(2).setCellValue(businessDataVO.getTurnover());
			row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
			row.getCell(6).setCellValue(businessDataVO.getNewUsers());

			row = sheet.getRow(4);
			row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
			row.getCell(4).setCellValue(businessDataVO.getUnitPrice());

			// 填充明细信息
			for (int i = 7; i < 37; i++) {
				LocalDate date = dateBegin.plusDays(1);
				BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
				row = sheet.getRow(i);
				row.getCell(1).setCellValue(date.toString());
				row.getCell(2).setCellValue(businessData.getTurnover());
				row.getCell(3).setCellValue(businessData.getValidOrderCount());
				row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
				row.getCell(5).setCellValue(businessData.getUnitPrice());
				row.getCell(6).setCellValue(businessData.getNewUsers());

			}

			// 通过输出流将将文件下载到客户端浏览器
			ServletOutputStream outputStream = response.getOutputStream();
			excel.write(outputStream);
			outputStream.close();
			excel.close();
			inputStream.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}
